package com.cv.platform.service.uv;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cv.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cv.platform.dal.dataobject.uv.CvDailyUvDO;
import com.cv.platform.dal.mapper.uv.CvDailyUvMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.cv.platform.dal.redis.RedisKeyConstants.DAILY_UV;

/**
 * 平台每日访客量计业务层接口实现类
 *
 * @author Charles_XDXD
 */
@Service
@Slf4j
public class CvDailyUvServiceImpl implements CvDailyUvService {

    @Resource
    private CvDailyUvMapper cvDailyUvMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public void syncDailyUv() {
        log.info("[CvDailyUvServiceImpl.syncDailyUv]: 开始同步平台每日访客量 UV 数据");

        // 获取昨日访客量
        LocalDate yesterday = LocalDate.now().minusDays(1);
        String key = DAILY_UV + yesterday;
        Long visitCount = Optional.ofNullable(redisTemplate.opsForHyperLogLog().size(key)).orElse(0L);

        // 新增数据
        CvDailyUvDO cvDailyUvDO = new CvDailyUvDO();
        cvDailyUvDO.setVisitCount(visitCount.intValue());
        cvDailyUvDO.setRecordDate(yesterday.atStartOfDay());
        try {
            cvDailyUvMapper.insert(cvDailyUvDO);
            log.info("[CvDailyUvServiceImpl.syncDailyUv]: 同步完毕，昨日访客量: {}", visitCount);
        } catch (Exception e) {
            log.error("[CvDailyUvServiceImpl.syncDailyUv] 同步数据失败: ", e);
        }

        // 清除缓存
        redisTemplate.opsForHyperLogLog().delete(key);
        log.info("[CvDailyUvServiceImpl.syncDailyUv]: 平台每日访客量 UV 数据同步完毕，已清除缓存数据");
    }

    @Override
    public Integer getTotalUv() {
        LambdaQueryWrapper<CvDailyUvDO> wrapper = new LambdaQueryWrapperX<CvDailyUvDO>()
                .select(CvDailyUvDO::getVisitCount);
        List<CvDailyUvDO> cvDailyUvDOS = cvDailyUvMapper.selectList(wrapper);
        int sum = cvDailyUvDOS.stream().mapToInt(CvDailyUvDO::getVisitCount).sum();
        String key = DAILY_UV + LocalDate.now();
        Long visitCount = Optional.ofNullable(redisTemplate.opsForHyperLogLog().size(key)).orElse(0L);
        return sum + visitCount.intValue();
    }

    @Override
    public List<Integer> getLastWeekUv() {
        // 生成上周所有日期（周一到周日）
        LocalDate start = LocalDate.now().minusWeeks(1).with(DayOfWeek.MONDAY);
        List<LocalDate> dateRange = IntStream.rangeClosed(0, 6)
                .mapToObj(start::plusDays)
                .toList();

        // 查询数据库数据并建立日期映射
        Map<LocalDate, Integer> uvMap = cvDailyUvMapper.selectList(new LambdaQueryWrapperX<CvDailyUvDO>()
                        .between(CvDailyUvDO::getRecordDate,
                                start.atStartOfDay(),
                                start.plusDays(6).atTime(LocalTime.MAX))
                        .select(CvDailyUvDO::getRecordDate, CvDailyUvDO::getVisitCount)
                ).stream()
                .collect(Collectors.toMap(
                        d -> d.getRecordDate().toLocalDate(),
                        CvDailyUvDO::getVisitCount
                ));

        // 按日期顺序填充数据（缺失则补0）
        return dateRange.stream()
                .map(date -> uvMap.getOrDefault(date, 0))
                .collect(Collectors.toList());
    }

}
